package org.jaronsource.framework.plugins.security.web.interceptor;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.jaronsource.framework.plugins.security.SecurityTokenHolder;
import org.jaronsource.framework.plugins.security.SecurityUtils;
import org.jaronsource.framework.plugins.security.domain.SecurityToken;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class SecurityInterceptor extends HandlerInterceptorAdapter {

	private String loginUrl = "/login";

	private String noPermUrl = "/noPermUrl";

	private Boolean needLogin = Boolean.TRUE;

	private Boolean local = Boolean.TRUE;

	@Override
	public boolean preHandle(	HttpServletRequest request,
								HttpServletResponse response,
								Object handler ) throws Exception {

		if ( ! ( handler instanceof HandlerMethod ) ) { return true; }

		SecurityToken token = SecurityTokenHolder.getSecurityToken();
		boolean userLogin = token != null;

		HandlerMethod handlerMethod = (HandlerMethod) handler;
		Method method = handlerMethod.getMethod();

		NeedLogin needLoginAnnotation = method.getAnnotation( NeedLogin.class );
		HasPerm hasPermAnnotation = method.getAnnotation( HasPerm.class );

		if ( !checkLogin( userLogin, needLoginAnnotation ) ) {
			response.sendRedirect( getLoginUrl( request ) );
			return false;
		}

		if ( !checkHasPerm( token, method, hasPermAnnotation ) ) {
			response.sendRedirect( getNoPermUrl( request ) );
			return false;
		}

		return true;

	}

	private boolean checkHasPerm(	SecurityToken token,
									Method method,
									HasPerm hasPermAnnotation ) {

		if ( hasPermAnnotation == null ) return true;

		String[] permCodes = hasPermAnnotation.code();
		if ( permCodes.length == 0 ) {
			permCodes = new String[] { method.getName() };
		}

		for ( String permCode : permCodes ) {
			if ( SecurityUtils.hasPerm( token, permCode ) ) return true;
		}

		return false;
	}

	private boolean checkLogin( boolean userLogin, NeedLogin needLoginAnnotation ) {
		if ( needLogin ) {
			if ( userLogin ) return true;
			else {
				if ( needLoginAnnotation != null && needLoginAnnotation.value() == false ) return true;
			}
		}

		else {
			if ( !userLogin && needLoginAnnotation != null && needLoginAnnotation.value() == true ) return false;
			return true;
		}

		return false;
	}

	public String getLoginUrl( HttpServletRequest request ) {
		if ( local ) return request.getContextPath() + loginUrl;
		return loginUrl;
	}

	public void setLoginUrl( String remoteLoginUrl ) {
		this.loginUrl = remoteLoginUrl;
	}

	public String getNoPermUrl( HttpServletRequest request ) {
		if ( local ) return request.getContextPath() + noPermUrl;
		return noPermUrl;
	}

	public void setNoPermUrl( String noPermUrl ) {
		this.noPermUrl = noPermUrl;
	}

	public Boolean getNeedLogin() {
		return needLogin;
	}

	public void setNeedLogin( Boolean needLogin ) {
		this.needLogin = needLogin;
	}

	public Boolean getLocal() {
		return local;
	}

	public void setLocal( Boolean local ) {
		this.local = local;
	}

}
